﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TaskParallelLibraryExample
{
    class Program
    {
        static void Main(string[] args)
        {
            TaskHandlingException exp = new TaskHandlingException();
        }

        private static string PrintTaskObjectState(object state)
        {
            Console.WriteLine(state.ToString());
            return "***WOWSERS***";
        }

        private void TaskInitializing()
        {
            //İnline initalizing
            Task<List<int>> taskWithInline = new Task<List<int>>(() =>
            {
                List<int> intList = new List<int>();
                for (int i = 0; i < 1000; i++)
                {
                    intList.Add(i);
                }
                return intList;
            });

            //actual method
            Task<string> taskWithActualMethod = new Task<string>(new Func<object, string>(PrintTaskObjectState), "This is task state couldnt be object");

            //create task retun list int usign task factory
            Task<List<int>> taskWithFactory = Task.Factory.StartNew<List<int>>((stateObj) =>
            {
                List<int> intList = new List<int>();
                for (int i = 0; i < 1000; i++)
                {
                    intList.Add(i);
                }
                return intList;
            }, 2000);

            //starting

            taskWithInline.Start();
            taskWithActualMethod.Start();

            Task.WaitAll(new Task[] { taskWithInline, taskWithActualMethod, taskWithFactory });

            //print results
            var taskInlineResult = taskWithInline.Result;
            Console.WriteLine(string.Format(
            "The task with inline Action<T> " +
            "returned a Type of {0}, with {1} items",
            taskInlineResult.GetType(),
            taskInlineResult.Count));
            taskWithInline.Dispose();

            //print results for taskWithInActualMethodAndState
            var taskWithInActualMethodResult = taskWithActualMethod.Result;
            Console.WriteLine(string.Format(
                "The task which called a Method returned '{0}'",
            taskWithInActualMethodResult.ToString()));
            taskWithActualMethod.Dispose();

            //print results for taskWithFactoryAndState
            var taskWithFactoryAndStateResult = taskWithFactory.Result;
            Console.WriteLine(string.Format(
                "The task with Task.Factory.StartNew<List<int>> " +
                "returned a Type of {0}, with {1} items",
                taskWithFactoryAndStateResult.GetType(),
                taskWithFactoryAndStateResult.Count));
            taskWithFactory.Dispose();

            Console.WriteLine("All done, press Enter to Quit");

            Console.ReadLine();
        }
    }

    public class TaskHandlingException
    {
        public TaskHandlingException()
        {
            // create the task
            Task<List<int>> taskWithFactoryAndState =
                Task.Factory.StartNew<List<int>>((stateObj) =>
                {
                    List<int> ints = new List<int>();
                    for (int i = 0; i < (int)stateObj; i++)
                    {
                        ints.Add(i);
                        if (i > 100)
                        {
                            InvalidOperationException ex =
                                new InvalidOperationException("oh no its > 100");
                            ex.Source = "taskWithFactoryAndState";
                            throw ex;
                        }
                    }
                    return ints;
                }, 2000);

            try
            {
                //use one of the trigger methods (ie Wait() to make sure AggregateException
                //is observed)
                taskWithFactoryAndState.Wait();
                if (!taskWithFactoryAndState.IsFaulted)
                {
                    Console.WriteLine(string.Format("managed to get {0} items",
                        taskWithFactoryAndState.Result.Count));
                }

            }
            catch (AggregateException aggEx)
            {
                foreach (Exception ex in aggEx.InnerExceptions)
                {
                    Console.WriteLine(string.Format("Caught exception '{0}'",
                        ex.Message));
                }
            }
            finally
            {
                taskWithFactoryAndState.Dispose();
            }

            Console.WriteLine("All done, press Enter to Quit");
            Console.ReadLine();
        }
    }
}
